/**
 *
 */

#include "Evolutive.h"

#include <evolutive/EvolutiveCaseGeneratorBuilder.h>
#include <evolutive/RandomCaseGen.h>
#include <evolutive/EventListener.h>
#include <evolutive/impl/MesoscopicTrafficSimulation.h>

#include <localview/LocalView.h>
#include <localview/Network.h>

#include <iostream>
#include <string>
#include <vector>
#include <stdio.h>

using namespace localview;

class MyEventListener : public EventListener {
public:
    MyEventListener() {
        output = fopen("output.csv", "w+");
        cases  = fopen("cases.csv", "w+");

        fprintf(cases, "Generation, Local Queue, Next Queue, Local Side Queue, Next Side Queue, Extensao Local, Proxima Extensao, Extensao Anterior, Fitness\n");
    }

    virtual ~MyEventListener() {
        fflush(output);
        fclose(output);
        fflush(cases);
        fclose(cases);
    }

    virtual void newGeneration(int id) {
        //std::cerr << "New generation" << "\n";
        curGeneration = id;
    }

    virtual void newCase(Case* parent1, Case* parent2, int childNum, Case* child, int crossOver, std::vector<int> mutations) {
    }

    virtual void generation(std::vector<Case*> cases) {
        float bestFitness = -1;
        float worstFitness = 999;
        float meanFitness = 0;
        float fitness = 0;

        for(int i = 0; i < cases.size(); i++) {

            logSimulatedCase(cases[i]);

            fitness = cases[i]->getFitness();

            if(fitness > bestFitness) {
                bestFitness = fitness;
            }

            if(fitness < worstFitness) {
                worstFitness = fitness;
            }

            meanFitness += fitness;
        }

        meanFitness = meanFitness/cases.size();

        fprintf(output, "%.2f, %.2f, %.2f\n", bestFitness, worstFitness, meanFitness);
    }

private:
    void logSimulatedCase(Case* c) {
        fprintf(cases, "%d, %d, %d, %d, %d, %d, %d, %d, %f\n",
                 curGeneration,
                 c->getResultLocalQueue(),
                 c->getResultNextQueue(),
                 c->getResultLocalSideQueue(),
                 c->getResultNextSideQueue(),
                 c->getLocalGreenExtension(),
                 c->getNextGreenExtension(),
                 c->getPreviousGreenExtension(),
                 c->getFitness());
    }
private:
    FILE* output;
    FILE* cases;
    int curGeneration;
};

void runEvolutive(localview::Network* net, std::string activeNode) {

    RandomCaseGen gen;
    LocalView localview(activeNode, net);

    EvolutiveCaseGeneratorBuilder builder;
    MyEventListener eventListener;
    EvolutiveCaseGenerator* evolutiveAlgorithm = builder.buildEvolutiveCaseGenerator();
    evolutiveAlgorithm->setEventListener(&eventListener);

    MesoscopicTrafficSimulation* simulator = (MesoscopicTrafficSimulation*)evolutiveAlgorithm->getLifeSimulator();
    simulator->enableLog();

    evolutiveAlgorithm->setNumInterations(30);

    std::vector<Case*> cases;

    for(int i = 0; i < 20; i++) {
        Case* c = gen.generate();
        c->setId(i);
        cases.push_back(c);
    }

    evolutiveAlgorithm->setLocalview(&localview);
    evolutiveAlgorithm->startEvolution(cases, 0);

    delete evolutiveAlgorithm;
}
